﻿#include "FITKGraphObjectAssemblyPoints.h"

// VTK
#include <vtkUnstructuredGrid.h>
#include <vtkPoints.h>

// For VTK 7
#include <vtkCellType.h>

// Graph
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

// Data
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"
#include "FITK_Interface/FITKInterfaceModel/FITKNodeList.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"

namespace Exchange
{
    FITKGraphObjectAssemblyPoints::FITKGraphObjectAssemblyPoints(AbaqusData::FITKDataCase* caseData, Interface::FITKAbaAssembly* assemblyData)
        : FITKGraphObject3D(caseData, assemblyData)
    {
        if (!assemblyData)
        {
            return;
        }

        // Initialize.
        init();

        // Generate the points data.
        bool flag = generatePolyData(assemblyData);
        if (!flag)
        {
            return;
        }

        // Generate the graph actors.
        generateGraph();

        // Set the layer need to be rendered.
        setRenderLayer(0);

        // Save if the bounds are fixed or dynamic.
        m_hasFixedBounds = false;

        // Save the graph object info.
        m_graphInfo.AssemblyId = assemblyData->getDataObjectID();
        m_graphInfo.Type = GraphDataType::AssemblyPointsGraph;
    }

    FITKGraphObjectAssemblyPoints::~FITKGraphObjectAssemblyPoints()
    {
        // Delete the grid data.
        deleteVtkObj(m_points);
        deleteVtkObj(m_ugrid);
    }

    void FITKGraphObjectAssemblyPoints::init()
    {
        // Create the grid data.
        m_points = vtkPoints::New();
        m_ugrid = vtkUnstructuredGrid::New();
        m_ugrid->SetPoints(m_points);
    }

    bool FITKGraphObjectAssemblyPoints::getFixedBounds(double* bounds)
    {
        if (!m_hasFixedBounds)
        {
            return false;
        }

        if (!m_ugrid)
        {
            return false;
        }

        double* bds = m_ugrid->GetBounds();

        for (int i = 0; i < 6; i++)
        {
            bounds[i] = bds[i];
        }

        return true;
    }

    void FITKGraphObjectAssemblyPoints::setPickable(bool isPickable, int dim)
    {
        if (m_fActor && (dim == -1 || dim == 0))
        {
            m_fActor->SetPickable(isPickable);
        }
    }

    void FITKGraphObjectAssemblyPoints::update(bool forceUpdate)
    {
        Q_UNUSED(forceUpdate);

        Interface::FITKAbaAssembly* assemblyData = dynamic_cast<Interface::FITKAbaAssembly*>(_dataObj);
        if (!assemblyData)
        {
            return;
        }

        // Clear data first.
        clearModelData();

        // Regenerate the points data.
        generatePolyData(assemblyData);

        // Update the actor.
        if (m_fActor)
        {
            m_fActor->update();
        }
    }

    void FITKGraphObjectAssemblyPoints::clearModelData()
    {
        // Reset grid data.
        resetVtkObj(m_points);
        resetVtkObj(m_ugrid);
    }

    bool FITKGraphObjectAssemblyPoints::generatePolyData(Interface::FITKAbaAssembly* assemblyData)
    {
        if (!m_points || !m_ugrid)
        {
            return false;
        }

        // Get the points.
        Interface::FITKNodeList* points = assemblyData->getPoints();
        if (!points)
        {
            return false;
        }

        // Get number of nodes.
        int nNode = points->getNodeCount();

        for (int i = 0; i < nNode; i++)
        {
            Core::FITKNode* node = points->getNodeAt(i);
            if (!node)
            {
                continue;
            }

            double pos[3]{ 0., 0., 0. };
            node->getCoor(pos);

            // Insert point and vertex cell.
            int ptId = m_points->InsertNextPoint(pos);

            vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
            cell->InsertNextId(ptId);
            m_ugrid->InsertNextCell(VTKCellType::VTK_VERTEX, cell);
        }

        return true;
    }

    void FITKGraphObjectAssemblyPoints::generateGraph()
    {
        if (!m_ugrid)
        {
            return;
        }

        // Create actor.
        m_fActor = FITKGraphActor::New();
        m_fActor->setActorType(ActorType::VertexActor);
        m_fActor->setDataType(DataType::MeshData);
        m_fActor->setGraphObject(this);
        m_fActor->SetPickable(false);
        m_fActor->SetVisibility(true);
        m_fActor->setScalarVisibility(false);
        m_fActor->setInputDataObject(m_ugrid);
        addActor(m_fActor);
    }
}   // namespace Exchange